﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

//Xử lý map
namespace MyGames
{
    class Map
    {
        static ContentManager content = GameLoader.Content;
        static Texture2D wayPointTexture = content.Load<Texture2D>(Const.TexturePathBackground + "Waypoint");

        #region Declaration
        Vector2 camerapostion;

        Locations location;
        List<Waypoint> wayPoints;
        List<ModelType> enemyTypes;
        List<Layer> layers;
        #endregion

        #region Properties
        public Locations Location
        {
            get { return location; }
        }

        public Vector2 CameraPosition
        {
            get { return camerapostion; }
            set
            {
                Vector2 pos = new Vector2();
                pos.X = MathHelper.Clamp(value.X, 0, Camera.WorldRectangle.Width - Camera.ViewPort.Width);
                pos.Y = MathHelper.Clamp(value.Y, 0, Camera.WorldRectangle.Height - Camera.ViewPort.Height);

                Vector2 s = pos - camerapostion;
                camerapostion = pos;

                foreach (Layer layer in layers)
                    layer.Position -= s * layer.Speed;
            }
        }

        public List<Layer> Layers
        {
            get { return layers; }
        }

        public List<ModelType> EnemyTypes
        {
            get { return enemyTypes; }
        }

        public List<Waypoint> Waypoints
        {
            get { return wayPoints; }
        }
        #endregion

        #region Constructor
        public Map()
        {
            wayPoints = new List<Waypoint>();
            layers = new List<Layer>();
            enemyTypes = new List<ModelType>();
        }
        #endregion

        #region Public methods
        public void UseThisWaypoint(Player player, Waypoint wp)
        {
            Locations old = location;
            LoadBackground(wp.NextLocation);

            foreach (Waypoint _wp in wayPoints)
                if (_wp.NextLocation == old)
                    player.WorldLocation = _wp.Coord;
        }

        public void LoadBackground(Locations loc)
        {
            // Clear old map
            layers.Clear();
            enemyTypes.Clear();
            wayPoints.Clear();

            // Load data from xml file
            MapData data = GameLoader.LoadMap(loc);

            // Init camera
            Camera.WorldRectangle = new Rectangle(0, 0, data.Width, 500);
            Camera.Position = Vector2.Zero;

            // Init map
            this.camerapostion = Vector2.Zero;
            this.location = data.Location;
            enemyTypes = data.EnemyTypes;

            foreach (WaypointInfo wi in data.WayPoints)
                wayPoints.Add(new Waypoint(wi));
            foreach (LayerInfo li in data.Layers)
                layers.Add(new Layer(li));

            // Play music
            // AudioManager.PlayBackgroundMusic(location);
        }
        #endregion

        #region Draw and Update
        public void Update(GameTime gameTime)
        {
            foreach (Waypoint wp in wayPoints)
                wp.Update(gameTime);
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            CameraPosition = Camera.Position;

            foreach (Waypoint wp in wayPoints)
                wp.Draw(spriteBatch);

            foreach (Layer layer in layers)
                layer.Draw(spriteBatch);
        }
        #endregion

        // --- Internal class --- //
        #region Internal Class
        internal class Layer
        {
            #region Declaration
            bool endless;
            float deep;
            Vector2 position;
            Texture2D texture;
            Vector2 speed;
            #endregion

            #region Properties
            public bool Endless
            {
                get { return endless; }
                set { endless = value; }
            }

            public float Deep
            {
                get { return deep; }
                set { deep = value; }
            }

            public Vector2 Position
            {
                get { return position; }
                set { position = value; }
            }

            public Vector2 Speed
            {
                get { return speed; }
                set { speed = value; }
            }

            public int TextureWidth
            {
                get { return texture.Width; }
            }

            public int TextureHeight
            {
                get { return texture.Height; }
            }

            public Texture2D Texture
            {
                get { return texture; }
                set { texture = value; }
            }

            public Rectangle SourceRectangle
            {
                get { return new Rectangle(0, 0, texture.Width, texture.Height); }
            }

            public Rectangle DestinyRectangle
            {
                get { return new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height); }
            }
            #endregion

            #region Constructor
            public Layer(Texture2D texture, Vector2 position, Vector2 speed, bool endless, float deep)
            {
                this.texture = texture;
                this.position = position;
                this.speed = speed;
                this.endless = endless;
                this.deep = deep;
            }

            public Layer(LayerInfo info)
                : this(content.Load<Texture2D>(Const.TexturePathBackground + info.TexturePath),
                    info.Position, info.Speed, info.Endless, info.Depth) { }
            #endregion

            #region Draw
            public void Draw(SpriteBatch spriteBatch)
            {
                if (Endless)
                {
                    Vector2 position = new Vector2(Position.X % TextureWidth, Position.Y);

                    for (int i = 0; i < 5;i++ )
                    {
                        spriteBatch.Draw(Texture, position + i* new Vector2(TextureWidth, 0f), SourceRectangle,
                                         Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, deep);
                    }

                }
                else
                {
                    if (DestinyRectangle.Intersects(new Rectangle(0, 0, Const.ScreenWidth, Const.ScreenHeight)))
                        spriteBatch.Draw(Texture, Position, SourceRectangle,
                                         Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, deep);
                }
            }
            #endregion
        }

        internal class Waypoint
        {
            #region Declaration
            AnimationStrip animation;
            Vector2 coord;
            Locations nextLocation;
            #endregion

            #region Properties
            public Rectangle WPRectangle
            {
                get
                {
                    return new Rectangle(
                        (int)coord.X - animation.FrameWidth / 2,
                        (int)coord.Y - animation.FrameHeight / 2,
                        animation.FrameWidth, animation.FrameHeight);
                }
            }

            public Locations NextLocation
            {
                get { return nextLocation; }
            }

            public Vector2 Coord
            {
                get { return coord; }
            }
            #endregion

            #region Constructor
            public Waypoint(int Xcoord, Locations nextLocation)
            {
                this.coord = new Vector2(Xcoord, 380);
                this.nextLocation = nextLocation;
                animation = new AnimationStrip(wayPointTexture, 1, 5, "waypoint");
                animation.LoopAnimation = true;
                animation.Play();
            }

            public Waypoint(WaypointInfo info) : this(info.XCoord, info.NextLocation) { }
            #endregion

            #region Update and Draw
            public void Update(GameTime gameTime)
            {
                animation.Update(gameTime);
            }

            public void Draw(SpriteBatch spriteBatch)
            {
                Vector2 og = new Vector2(animation.FrameWidth / 2, animation.FrameHeight);
                spriteBatch.Draw(animation.Texture, Camera.WorldToScreen(coord), animation.FrameRectangle,
                    Color.White, 0f, og, 1f, SpriteEffects.None, 0.9f);
            }
            #endregion
        }
        #endregion
    }
}
